package com.beidouapp.translator;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beidouapp.cache.CacheTranslator;
import com.beidouapp.domain.annotation.TranslateField;
import com.beidouapp.exception.BusinessException;
import com.beidouapp.exception.ErrorCodes;
import com.beidouapp.translate.Translatable;
import com.beidouapp.translate.Translator;

public class DefaultTranslatorManager implements TranslatorManager
{
    private static final Logger logger = LoggerFactory.getLogger(DefaultTranslatorManager.class);
    
    private final static Map <String, Translator> s_translators = new HashMap <String, Translator> ();

    private final static Map <String, List <Field>> s_className2TranslatedFieldMap = new HashMap <String, List <Field>> ();

    protected Translator getTranslator (String translatorName)
    {
        return s_translators.get (translatorName);
    }

    private void chcheTranslateFieldList (Class < ? > clazz)
    {
        List <Field> translateFieldList = s_className2TranslatedFieldMap.get (clazz.getName ());
        if (translateFieldList == null)
        {
            translateFieldList = new ArrayList <Field> ();
            Field[] fields = clazz.getDeclaredFields ();

            for (Field codeField : fields)
            {
                TranslateField annotation = codeField.getAnnotation (TranslateField.class);
                if (annotation != null)
                {
                    translateFieldList.add (codeField);
                    logger.debug("found one filed:[" + codeField.getName () + "]");
                }
            }

            s_className2TranslatedFieldMap.put (clazz.getName (), translateFieldList);
        }
    }

    @Override
    public <T extends Translatable> T translate (T object)
    {
        StringBuilder errorMessage = new StringBuilder ();
        Class < ? > clazz = object.getClass ();
        chcheTranslateFieldList (clazz);

        List <Class < ? >> classList = new ArrayList <Class < ? >> ();
        classList.add (clazz);

        while (null != clazz.getSuperclass ())
        {
            clazz = clazz.getSuperclass ();
            chcheTranslateFieldList (clazz);
            classList.add (clazz);
        }

        for (Class < ? > tempClazz : classList)
        {
            List <Field> translateFieldList = s_className2TranslatedFieldMap.get (tempClazz.getName ());
            for (Field sourceField : translateFieldList)
            {
                try
                {
                    sourceField.setAccessible (true);
                    Object sourceFieldValueAsObject = sourceField.get (object);
                    String sourceFieldValue, targetFieldValue = null;

                    if (sourceFieldValueAsObject == null || sourceFieldValueAsObject.equals (""))
                    {
                        sourceFieldValue = null;
                        continue;
                    }
                    else
                    {
                        sourceFieldValue = sourceFieldValueAsObject.toString ();
                    }

                    TranslateField annotation = sourceField.getAnnotation (TranslateField.class);
                    String translatorName = annotation.translatorName ();
                    if (translatorName == null || translatorName.equals (""))
                    {
                        errorMessage.setLength (0);
                        errorMessage.append ("translator not found.[translatorName:");
                        errorMessage.append (translatorName);
                        errorMessage.append (",domainObject=");
                        errorMessage.append (tempClazz.getName ());
                        errorMessage.append ("]");

                        throw new BusinessException (ErrorCodes.TranslatorNotFound, errorMessage.toString ());
                    }

                    String targetFieldName = annotation.targetFieldName ();
                    if (targetFieldName == null || targetFieldName.equals (""))
                    {
                        errorMessage.setLength (0);
                        errorMessage.append ("translate annotation missing targetFieldName.[domainObject:");
                        errorMessage.append (tempClazz.getName ());
                        errorMessage.append ("]");
                        throw new BusinessException (ErrorCodes.MissingTargetFieldName,
                                                     errorMessage.toString ());
                    }

                    String fullQualifiedName = annotation.fullQualifiedName ();
                    if (fullQualifiedName == null || fullQualifiedName.equals (""))
                    {
                        fullQualifiedName = DICT_CACHENODE_PATH + translatorName;
                    }

                    if (DICT_TRANSLATOR_NAME.equals (translatorName))
                    {
                        targetFieldValue = getTranslator (translatorName).translate (fullQualifiedName,
                                                                                     sourceFieldValue);
                    }
                    else
                    {
                        Translator translatorReference = getTranslator (translatorName);
                        if (!(translatorReference instanceof CacheTranslator))
                        {
                            errorMessage.setLength (0);
                            errorMessage.append ("translator can't found.[translatorName:");
                            errorMessage.append (CACHE_TRANSLATOR_NAME);
                            errorMessage.append (",domainObject=");
                            errorMessage.append (tempClazz.getName ());
                            errorMessage.append ("]");

                            throw new BusinessException (ErrorCodes.TranslatorNotFound,
                                                         errorMessage.toString ());
                        }

                        CacheTranslator cacheTranslator = (CacheTranslator) translatorReference;
                        if (!cacheTranslator.isExistItem (fullQualifiedName, sourceFieldValue))
                        {
                            Translator translator = getTranslator (translatorName);
                            if (translator != null)
                            {
                                logger.debug("One translator matched.[" + translatorName + "]");
                                targetFieldValue = translator.translate (translatorName, sourceFieldValue);
                                if (targetFieldValue != null)
                                {
                                    cacheTranslator.addItem (fullQualifiedName, sourceFieldValue, targetFieldValue);
                                }
                            }
                            else
                            {
                                errorMessage.setLength (0);
                                errorMessage.append ("translator can't found.[translatorName:");
                                errorMessage.append (translatorName);
                                errorMessage.append (",domainObject=");
                                errorMessage.append (tempClazz.getName ());
                                errorMessage.append ("]");

                                throw new BusinessException (ErrorCodes.TranslatorNotFound,
                                                             errorMessage.toString ());
                            }
                        }
                        else
                        {
                            targetFieldValue = cacheTranslator.translate (fullQualifiedName, sourceFieldValue);
                        }
                    }

                    Field targetField = tempClazz.getDeclaredField (targetFieldName);
                    targetField.setAccessible (true);
                    targetField.set (object, targetFieldValue);

                    logger.debug("Translate field " + sourceField.getName () + " to " + targetField.getName ()
                                 + ", sourceFieldValue:" + sourceFieldValue + " , targetFieldValue:" + targetFieldValue);
                }
                catch (Throwable e)
                {
                    e.printStackTrace ();
                    errorMessage.setLength (0);
                    errorMessage.append ("translate occur exception.[");
                    errorMessage.append ("domainObject=");
                    errorMessage.append (tempClazz.getName ());
                    errorMessage.append ("]");

                    throw new BusinessException (ErrorCodes.TranslateUnknownException,
                                                 errorMessage.toString (), e);
                }
            }
        }
        return object;
    }

    /**
     * 缈昏瘧瀵硅薄涓渶瑕佽缈昏瘧鐨勫瓧娈�
     */
    @Override
    public <T extends Translatable> List <T> translate (List <T> lists)
    {
        for (T t : lists)
        {
            translate (t);
        }
        return lists;
    }

    /**
     * 娣诲姞缈昏瘧鍣�
     */
    @Override
    public void addTranslator (Translator translator)
    {

        if (!s_translators.containsKey (translator.getTranslatorName ()))
        {
            logger.debug("add translator:" + translator.getTranslatorName ());
            s_translators.put (translator.getTranslatorName (), translator);
        }
    }

    /**
     * 绉婚櫎缈昏瘧鍣�
     */
    @Override
    public void removeTranslator (Translator translator)
    {
        if (s_translators.containsKey (translator.getTranslatorName ()))
        {
            logger.debug("remove translator.[" + translator.getTranslatorName () + "]");
            s_translators.remove (translator.getTranslatorName ());
        }
    }
}
